//
//  CommunicationManager.m
//  CoolMove
//
//  Created by CA on 14-9-11.
//  Copyright (c) 2014年 CA. All rights reserved.
//

#import "CommunicationManager.h"


NSString * const kCommunicationMangaerModifyNameNotification = @"kCommunicationMangaerModifyNameNotification";

typedef void(^ScanFirstFeedbackBlock)(NSString *dateStr,            // 日期
                                      NSNumber *calories,           // 卡路里
                                      NSNumber *exerciseAmount,     // 运动量
                                      NSNumber *timeInterval,       // 运动时间
                                      NSNumber *countOfSessions);   // 场次

typedef void(^ScanSecondFeedbackBlock)(NSNumber *smashCount,        // 扣次数
                                       NSNumber *blockCount,        // 挡次数
                                       NSNumber *dropCount,         // 挑次数
                                       NSNumber *emptyCount,        // 空挥次数
                                       NSNumber *maxSpeed,          // 最大速度
                                       NSNumber *clearCount,        // 高球次数
                                       NSNumber *driveCount,        // 平抽次数
                                       NSNumber *chopCount);        // 最大速度


#pragma mark - 酷浪小羽2s Nordic -

static NSString * const kNewOperationService = @"0001";
static NSString * const kNewNotifyCharacteristic = @"0003";
static NSString * const kNewWriteCharacteristic = @"0002";
static NSString * const kNewReadCharacteristic = @"0004";

#pragma mark - DFU

static NSString * const dfuServiceUUIDString = @"00001530-1212-efde-1523-785feabcd123";
static NSString * const dfuControlPointCharacteristicUUIDString = @"00001531-1212-efde-1523-785feabcd123";
static NSString * const dfuMacReadUUIDString = @"00001533-1212-efde-1523-785feabcd123";


@interface CommunicationManager (){
    NSMutableArray *homePageArr; //运动主界面数据保存统一处理
    BOOL isReponsed; //实时指令发送后5秒是否被应答
}

@property (nonatomic, copy) CompletionBlock connectBlock;

@property (nonatomic, strong) LGCharacteristic *deviceNewWriteCharacterstic;
@property (nonatomic, strong) LGCharacteristic *deviceNewNotifyCharacterstic;
@property (nonatomic, strong) LGCharacteristic *deviceNewReadCharacterstic;

@property (nonatomic, strong) LGCharacteristic *dfuMacReadCharacterstic;
@property (nonatomic, strong) LGCharacteristic *dfuControlPointCharacterstic;

@property (nonatomic, copy) OperationBlock operationBlock;

@end

@implementation CommunicationManager

+ (instancetype)shareInstance
{
    static id shareInstsance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareInstsance = [[self alloc] init];
    });
    
    return shareInstsance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _shouldRetryConnect = YES;
    }
    return self;
}

#pragma mark - Getter/Setter

- (BOOL)isPeripheralConnected
{

    if ([CommunicationManager shareInstance].lgPeripheral.isConnected) {
        return YES;
    } else {
        
        NSString *message =NSLocalizedStringFromTable(@"Device is not connected", @"Location", nil);
        
#if IsOEM
        message = NSLocalizedStringFromTable(@" Device is not connected ", @"Location", nil);
#endif
        
        FUIAlertView *alertView = [[FUIAlertView alloc] initWithTitle:NSLocalizedStringFromTable(@"Attention", @"Location", nil) message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedStringFromTable(@"Yes", @"Location", nil), nil];
        [alertView customizeAppearance];
        [alertView show];
        
        return NO;
    }
}

- (BOOL)isPeripheralConnectedWithoutAlertView
{
    return [CommunicationManager shareInstance].lgPeripheral.isConnected;
}

- (BOOL)isCentralReady
{
    BOOL isReady = [LGCentralManager sharedInstance].isCentralReady;
    if (!isReady) {
        FUIAlertView *alert = [[FUIAlertView alloc] initWithTitle:NSLocalizedString(@"Reminder", nil) message:NSLocalizedString(@"Please turn on Bluetooth  and allow Smart Tennis to use it", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"Yes", nil) otherButtonTitles: nil];
        [alert customizeAppearance];
        [alert show];
    }
    
    return isReady;
}

- (NSNumber *)batteryValue
{
    if ([self isPeripheralConnectedWithoutAlertView]) {
        return _batteryValue;
    } else {
        return @0;
    }
}

- (BOOL)isDFUMode
{
    return (self.dfuMacReadCharacterstic || self.dfuControlPointCharacterstic);
}

#pragma mark - Public Method

- (void)connectPeripheral:(LGPeripheral *)peripheral completion:(CompletionBlock)block
{
    self.lgPeripheral = peripheral;
    self.connectBlock = block;
    
    __weak CommunicationManager *weakSelf = self;
    [peripheral connectWithCompletion:^(NSError *error) {
        
        if (!error) {
            weakSelf.shouldRetryConnect = YES;
            [weakSelf setupServicesWithPeripheral:peripheral completion:block];
        } else {
            block(NO);
        }
    }];
}

- (void)connectWithoutRetryConnectPeripheralUUID:(NSString *)uuidStr completion:(CompletionBlock)block
{
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidStr];
    LGPeripheral * peripheral = [[[LGCentralManager sharedInstance] retrievePeripheralsWithIdentifiers:@[uuid]] lastObject];
    __weak CommunicationManager *weakSelf = self;
    [peripheral connectWithCompletion:^(NSError *error) {
        if (!error) {
            [weakSelf setupServicesWithPeripheral:peripheral completion:block];
        }
    }];
}

- (void)setupServicesWithPeripheral:(LGPeripheral *)peripheral completion:(CompletionBlock)block
{
    self.connectBlock = block;
    
    [self defaultCharacteristicSetting];
    
    self.lgPeripheral = peripheral;
    
    __weak CommunicationManager *weakSelf = self;
    
    [peripheral discoverServicesWithCompletion:^(NSArray *services, NSError *error) {
        
        for (LGService *service in services) {
            NSLog(@"serve uuidString:%@", service.UUIDString);
            
            if ([service.UUIDString isEqualToString:kNewOperationService]) {
                
                [service discoverCharacteristicsWithCompletion:^(NSArray *characteristics, NSError *error) {
                    
                    for (LGCharacteristic *characteristic in characteristics) {
                        NSLog(@"characteristic:%@", characteristic.UUIDString);
                        
                        if ([characteristic.UUIDString isEqualToString:kNewWriteCharacteristic]) {
                            weakSelf.deviceNewWriteCharacterstic = characteristic;
                            
                            [weakSelf checkIfAllReady];
                        } else if ([characteristic.UUIDString isEqualToString:kNewNotifyCharacteristic]) {
                            weakSelf.deviceNewNotifyCharacterstic = characteristic;
                            
                            [characteristic setNotifyValue:YES completion:nil onUpdate:^(NSData *data, NSError *error) {
                                
                                [weakSelf handleData:data];
                                [weakSelf checkIfAllReady];
                            }];
                            
                            
                        } else if ([characteristic.UUIDString isEqualToString:kNewReadCharacteristic]) {
                            weakSelf.deviceNewReadCharacterstic = characteristic;
                            
                            [characteristic readValueWithBlock:^(NSData *data, NSError *error) {
                                if (!error) {
                                    peripheral.macAddress = [self convertNewMacAddressWithData:data];
                                    
                                    NSLog(@"mac data:%@", peripheral.macAddress);
                                    
                                    [weakSelf checkIfAllReady];
                                }
                            }];
                        }
                    }
                    
                }];
                
            } else if ([service.UUIDString isEqualToString:dfuServiceUUIDString]) {
                [service discoverCharacteristicsWithCompletion:^(NSArray *characteristics, NSError *error) {
                    
                    for (LGCharacteristic *characteristic in characteristics) {
                        NSLog(@"characteristic:%@", characteristic.UUIDString);
                        
                        if ([characteristic.UUIDString isEqualToString:dfuMacReadUUIDString]) {
                            weakSelf.dfuMacReadCharacterstic = characteristic;
                            
                            [weakSelf checkIfAllReady];
                            
                        } else if ([characteristic.UUIDString isEqualToString:dfuControlPointCharacteristicUUIDString]) {
                            weakSelf.dfuControlPointCharacterstic = characteristic;
                            
                            [weakSelf checkIfAllReady];
                        }
                    }
                    
                }];
            }
        }
        
    }];
}

- (void)recoverPeripheralWithUUIDString:(NSString *)UUIDString completionBlock:(CompletionBlock)block
{
    [self defaultCharacteristicSetting];
    
    if (!self.shouldRetryConnect) {
        return;
    }
    
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:UUIDString];
    
    if (uuid == nil) {
        return;
    }
    
    LGPeripheral *peripheral = [[[LGCentralManager sharedInstance] retrievePeripheralsWithIdentifiers:@[uuid]] lastObject];
    
    [self connectPeripheral:peripheral completion:block];
}

- (void)stopScanningPeripherals
{
    if ([LGCentralManager sharedInstance].isScanning) {
        [[LGCentralManager sharedInstance] stopScanForPeripherals];
    }
}

- (void)checkIfAllReady
{
    if (self.deviceNewNotifyCharacterstic && self.deviceNewWriteCharacterstic && self.deviceNewReadCharacterstic && self.connectBlock) {
        self.connectBlock(YES);
        self.connectBlock = nil;
        
        [self stopScanningPeripherals];
        return;
    } else if (self.dfuMacReadCharacterstic && self.dfuControlPointCharacterstic && self.connectBlock) {
        self.connectBlock(YES);
        self.connectBlock = nil;
        return;
    }

}

- (void)disconnectThePeripheralWithCompletionBlock:(CompletionBlock)block
{
    if (self.lgPeripheral.isConnected) {
        [self.lgPeripheral disconnectWithCompletion:^(NSError *error) {
            if (!error) {
                block(YES);
                
                [[NSNotificationCenter defaultCenter] postNotificationName:kLGPeripheralDidDisconnect object:nil];
            }
        }];
        
    } else {
        block(YES);
    }
    
    
}


#pragma mark - APP -> 轮滑

- (void)performOperationType:(OperationType)operationType object:(id)object completionBlock:(OperationBlock)block
{
    NSData *data = [self dataWithOperationType:operationType object:object];
    if (data == nil) {
        return;
    }
    [self.deviceNewWriteCharacterstic writeValue:data completion:^(NSError *error) {
        NSLog(@"functionCode:%d",[self getFunctionCodeByOperationType:operationType]);
        if (!error) {
            NSLog(@"发送特征值数据:%@",data);
            if (self.operationBlock) {
                self.operationBlock(NO,nil);
            }
            self.operationBlock = block;
        }
    }];
    
}

- (NSData *)dataWithOperationType:(OperationType)operationType object:(id)object
{
    switch (operationType) {
        case OperationTypeVerify:
            return [self getTimeVerifyData];
            break;
        case OperationTypeChangeDeviceName:
            return [self modifyDeviceNameByModifyName:object];
            break;
        case OperationTypeBatteryRead:
            return [self getBatteryData];
            break;
        case OperationTypeRestartDevice:
            return [self getRestartData];
            break;
        case OperationTypeCloseDevice:
            return [self getCloseData];
            break;
        case OperationTypeUpdateDevice:
            return [self getUpdateData];
            break;
        case OperationTypeCleanData:
            return [self getCleanData];
            break;
        case OperationTypeResetDevice:
            return [self getResetData];
            break;
        case OperationTypeDeviceVersion:
            return [self getDeviceVersionData];
            break;
        case OperationTypeHand:
            return [self getHandData:object];
            break;
        case OperationTypeReadRunTimeData:
            return [self getRuntimeData];
            break;
        case OperationTypeQuitRunTime:
            return [self quitRuntime];
            break;
        case OperationTypeReadHomePageData:
            return [self getHomePageData];
            break;
        case OperationTypeReadSportDetailData:
            return [self getSportDatailData:object];
            break;
        
        default:
            return nil;
            break;
    }
}

#pragma mark - Public Get Data

- (Byte)getFunctionCodeByOperationType:(OperationType)operationType
{
    Byte functionByte;
    switch (operationType) {
        case OperationTypeVerify:
            functionByte = 0x11;
            break;
        case OperationTypeChangeDeviceName:
            functionByte = 0x12;
            break;
        case OperationTypeBatteryRead:
            functionByte = 0x22;
            break;
        case OperationTypeRestartDevice:
            functionByte = 0x02;
            break;
        case OperationTypeCloseDevice:
            functionByte = 0x01;
            break;
        case OperationTypeUpdateDevice:
            functionByte = 0x05;
            break;
        case OperationTypeCleanData:
            functionByte = 0x03;
            break;
        case OperationTypeResetDevice:
            functionByte = 0x04;
            break;
        case OperationTypeDeviceVersion:
            functionByte = 0x21;
            break;
        case OperationTypeHand:
            functionByte =0x13;
            break;
        case OperationTypeReadRunTimeData:
            [self performSelector:@selector(isReponsed) withObject:nil afterDelay:5.0];
            functionByte = 0x24;
            break;
        case OperationTypeQuitRunTime:
            functionByte = 0x24;
            break;
        case OperationTypeReadHomePageData:
            homePageArr = @[].mutableCopy;
            functionByte =0x23;
            break;
        case OperationTypeReadSportDetailData:
            functionByte = 0x25;
            break;
        
        default:
            break;
    }
    return functionByte;
}

- (NSData *)getDataByOperationType:(OperationType)operationType
{
    Byte bytes[20];
    bytes[0] = 0xA8;
    bytes[1] = [self getFunctionCodeByOperationType:operationType];
    bytes[2] = 0x00;
    for (NSUInteger index = 3; index < 19; index++) {
        bytes[index] = 0x00;
    }
    bytes[19] = [self modulusValue:bytes countOfBytes:sizeof(bytes)];
    
    NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
    
    return data;
}

- (NSData *)getDataByOperationType:(OperationType)operationType parame:(Byte)parame
{
    Byte bytes[20];
    bytes[0] = 0xA8;
    bytes[1] = [self getFunctionCodeByOperationType:operationType];
    bytes[2] = parame;
    for (NSUInteger index = 3; index < 19; index++) {
        bytes[index] = 0x00;
    }
    bytes[19] = [self modulusValue:bytes countOfBytes:sizeof(bytes)];
    
    NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
    
    return data;
}

- (NSData *)getDataByOperationType:(OperationType)operationType parame:(Byte)parame oemType:(OemType)type
{
    Byte bytes[20];
    bytes[0] = 0xA8;
    bytes[1] = [self getFunctionCodeByOperationType:operationType];
    bytes[2] = parame;
    bytes[3] = [self getFirmwareVersionByteWithOemType:type];
    for (NSUInteger index = 4; index < 19; index++) {
        bytes[index] = 0x00;
    }
    bytes[19] = [self modulusValue:bytes countOfBytes:sizeof(bytes)];
    
    NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
    
    return data;
}

- (Byte)getFirmwareVersionByteWithOemType:(OemType)type
{
    if (type == OemTypeTS) {
        return (Byte)0xFE;
    }else if (type == OemTypeT5){
        return (Byte)0x05;
    }else {
        return (Byte)type;
    }
}

#pragma mark - 修改设备名字

- (NSData *)modifyDeviceNameByModifyName:(NSString *)modifyName
{
    if (![self checkModifyNameLength:modifyName]) {
        [self showOverLengthAlertView];
        return nil;
    }
    
    NSData *modifyNameData = [self modifyNameDataWithModifyName:modifyName];
    NSLog(@"modify name:%@", modifyNameData);
    return modifyNameData;
}

- (void)showOverLengthAlertView
{
    FUIAlertView *alertView = [[FUIAlertView alloc] initWithTitle:NSLocalizedStringFromTable(@"Reminder", @"Location", nil) message:NSLocalizedStringFromTable(NSLocalizedString(@"Name required less than 17 letters or numbers", nil), @"Location", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
    [alertView customizeAppearance];
    [alertView show];
}

- (BOOL)checkModifyNameLength:(NSString *)name
{
    NSData *nameData = [name dataUsingEncoding:NSUTF8StringEncoding];
    if (nameData.length > 17) {
        return NO;
    }
    
    return YES;
}

- (NSData *)modifyNameDataWithModifyName:(NSString *)modifyName
{
    Byte bytes[20];
    bytes[0] = 0xA8;
    bytes[1] = 0x12;
    
    NSMutableData *nameData = [[modifyName dataUsingEncoding:NSUTF8StringEncoding] mutableCopy];
    NSInteger nameLength = [nameData length];
    //设备名称不能超过17字节，少于17字节的，要以空格（0x20）补齐
    if (nameLength < 17) {
        Byte bytes[1];
        bytes[0] = 0x20;
        NSData *spaceData = [NSData dataWithBytes:bytes length:1];
        
        for (NSUInteger index = 0; index < 17 - nameLength; index++) {
            [nameData appendData:spaceData];
        }
    }
    
    const u_int8_t *value = [nameData bytes];
    for (NSUInteger index = 0; index < 17; index++) {
        bytes[2 + index] = (Byte)value[index];
    }
    
    bytes[19] = [self modulusValue:bytes countOfBytes:sizeof(bytes)];
    NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
    NSLog(@"修改名字 data:%@", data);
    
    return data;
}

#pragma mark - 读取电量

- (NSData *)getBatteryData
{
    return [self getDataByOperationType:OperationTypeBatteryRead];
}

#pragma mark - 重启设备

- (NSData *)getRestartData
{
    return [self getDataByOperationType:OperationTypeRestartDevice];
}

#pragma mark - 关闭设备

- (NSData *)getCloseData
{
    return [self getDataByOperationType:OperationTypeCloseDevice];
}

#pragma mark - 固件升级

- (NSData *)getUpdateData
{
    return [self getDataByOperationType:OperationTypeUpdateDevice parame:0x02 oemType:self.lgPeripheral.oemType];
}

#pragma mark - 清除数据

- (NSData *)getCleanData
{
    return [self getDataByOperationType:OperationTypeCleanData];
}

#pragma mark - 恢复出厂

- (NSData *)getResetData
{
    return [self getDataByOperationType:OperationTypeResetDevice];
}

- (NSData *)getDeviceVersionData
{
    return [self getDataByOperationType:OperationTypeDeviceVersion];
}

#pragma mark - Handler

- (BOOL)verifyValidData:(NSData *)data functionByte:(Byte)functionByte
{
    const u_int8_t *bytes = [data bytes];
    if (bytes[1] != functionByte) {
        return NO;
    }
    
    Byte verify = [self modulusValue:(Byte *)bytes countOfBytes:[data length]];
    if (verify == bytes[[data length] - 1]) {
        
        return YES;
    }
    
    return NO;
}

#pragma mark - 左右手设置
- (NSData *)getHandData:(id)handtype
{
    NSString *hand = handtype;
    return [self getDataByOperationType:OperationTypeHand parame:[hand integerValue]];
}

#pragma mark - 实时数据/退出实时
- (NSData *)getRuntimeData
{
    return [self getDataByOperationType:OperationTypeReadRunTimeData];
}

- (void)isReponsed {
    if (!isReponsed) {
        [self performOperationType:OperationTypeReadRunTimeData object:nil completionBlock:self.operationBlock];
        isReponsed = NO;
    }
}

- (NSData *)quitRuntime
{
    self.operationBlock = nil;
    return [self getDataByOperationType:OperationTypeQuitRunTime parame:0x02];
}

#pragma mark - 读取主界面数据
- (NSData *)getHomePageData
{
    return [self getDataByOperationType:OperationTypeReadHomePageData];
}

#pragma mark - 读取运动详情数据
- (NSData *)getSportDatailData:(NSDictionary *)parame
{
    Byte bytes[20];
    bytes[0] = 0xA8;
    bytes[1] = [self getFunctionCodeByOperationType:OperationTypeReadSportDetailData];
    NSInteger timeStamp = [parame[@"SportRecordItem.UnixTimeStamp"] integerValue]/86400;
    bytes[2] = timeStamp/256;
    bytes[3] = timeStamp%256;
    NSInteger item = [parame[@"BarChartItem.Index"] integerValue];
    bytes[4] = item / 256;
    bytes[5] = item % 256;
    bytes[19] = [self modulusValue:bytes countOfBytes:sizeof(bytes)];
    
    NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
    
    return data;
}

#pragma mark - 时间校准
- (NSData *)getTimeVerifyData
{
    NSDate *date = [NSDate date];
    NSTimeZone *zone = [NSTimeZone localTimeZone];
    NSTimeInterval time = [zone secondsFromGMTForDate:date];
    NSDate *date1 = [date dateByAddingTimeInterval:time];
    long long timeStamp = [date1 unixTimeStamp];

    Byte bytes[20];
    bytes[0] = 0xA8;
    bytes[1] = [self getFunctionCodeByOperationType:OperationTypeVerify];
    bytes[2] = timeStamp /(256 * 256 * 256);
    bytes[3] = timeStamp /(256 * 256);
    bytes[4] = timeStamp /256;
    bytes[5] = timeStamp % 256;
    bytes[19] = [self modulusValue:bytes countOfBytes:sizeof(bytes)];
    
    return [NSData dataWithBytes:bytes length:sizeof(bytes)];
}

#pragma mark - 轮滑 -> APP


#pragma mark - Private Method

// 获得对256求模的值
- (Byte)modulusValue:(Byte *)bytes countOfBytes:(NSInteger)size
{
    NSUInteger total = 0;
    
    for (NSInteger index = 0; index < size - 1; index++) {
        total += bytes[index];
    }
    
    return total % 256;
}

// 处理球拍返回的数据
- (void)handleData:(NSData *)data
{
    NSLog(@"handle data:%@", data);
    
    if ([data length] > 3) {
        const u_int8_t *bytes = [data bytes];
        Byte functionByte = bytes[1];
        if (![self verifyValidData:data functionByte:functionByte]) {
            if (self.operationBlock) {
                self.operationBlock(NO, nil);
                self.operationBlock = nil;
            }
        }
        
        switch (bytes[1]) {
            case 0x23:
                if (bytes[2] != 0x03) {
                    [homePageArr addObject:data];
                } else {
                    [homePageArr addObject:data];
                    self.operationBlock(YES,homePageArr);
                }
                return;
                break;
            case 0x24:
                if (bytes[2] == 0x00) {
                    isReponsed = YES;
                    return;
                }
                break;
            case 0x05:
                if (self.operationBlock) {
                    self.operationBlock(YES, data);
                    self.operationBlock = nil;
                }
                break;
            case 0x12:
                if (self.operationBlock) {
                    self.operationBlock(YES, data);
                    self.operationBlock = nil;
                }
                break;
            default:
                break;
        }

        if (self.operationBlock) {
            self.operationBlock(YES, data);
        }
       
    }
}

- (void)defaultCharacteristicSetting
{
    self.deviceNewNotifyCharacterstic = nil;
    self.deviceNewWriteCharacterstic = nil;
    self.deviceNewReadCharacterstic = nil;
    
    self.dfuMacReadCharacterstic = nil;
    self.dfuControlPointCharacterstic = nil;
}

#pragma mark - 转换mac地址

- (NSString *)convertFeedbackMacAddressWithData:(NSData *)data
{
    if ([data length] != 20) {
        return nil;
    }
    
    const u_int8_t *bytes = [data bytes];
    NSMutableString *valueString = [[NSMutableString alloc] initWithString:@""];
    for (NSInteger index = 3; index < [data length] - 2; index++) {
        
        u_int8_t asciiCode = bytes[index];
        NSString *toValueString = [NSString stringWithFormat:@"%c", asciiCode];
        [valueString appendString:toValueString];
    }
    
    return valueString;
}

- (NSString *)convertNewMacAddressWithData:(NSData *)data
{
    if ([data length] != 6) {
        return nil;
    }
    
    const u_int8_t *bytes = [data bytes];
    NSMutableString *valueString = [[NSMutableString alloc] initWithString:@""];
    for (NSInteger index = [data length] - 1; index >= 0; index--) {
        
        u_int8_t value = bytes[index];
        u_int8_t firstValue = value/16;
        u_int8_t secondValue = value%16;
        
        NSString *toFirstValueString = [self toValueStringWithValue:firstValue];
        NSString *toSecondValueString = [self toValueStringWithValue:secondValue];
        [valueString appendString:toFirstValueString];
        [valueString appendString:toSecondValueString];
    }
    
    return valueString;
}

- (NSString *)convertMacAddressWithData:(NSData *)data
{
    if ([data length] != 8) {
        return nil;
    }
    
    const u_int8_t *bytes = [data bytes];
    NSMutableString *valueString = [[NSMutableString alloc] initWithString:@""];
    for (NSInteger index = [data length] - 1; index >= 0; index--) {
        
        if (index == 3 || index == 4) {
            continue;
        }
        
        u_int8_t value = bytes[index];
        u_int8_t firstValue = value/16;
        u_int8_t secondValue = value%16;
        
        NSString *toFirstValueString = [self toValueStringWithValue:firstValue];
        NSString *toSecondValueString = [self toValueStringWithValue:secondValue];
        [valueString appendString:toFirstValueString];
        [valueString appendString:toSecondValueString];
    }
    
    return valueString;
}

- (NSString *)toValueStringWithValue:(u_int8_t)value
{
    switch (value) {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
            return [@(value) stringValue];
            break;
        case 10:
            return @"A";
            break;
        case 11:
            return @"B";
            break;
        case 12:
            return @"C";
            break;
        case 13:
            return @"D";
            break;
        case 14:
            return @"E";
            break;
        case 15:
            return @"F";
            break;
            
        default:
            return @"";
            break;
    }
}

@end
